﻿\subsubsection{Структура как набор переменных}

Чтобы проиллюстрировать то что структура ~--- это просто набор переменных, лежащих в одном месте, 
переделаем немного пример, еще раз заглянув в описание структуры \IT{tm}: \lstref{struct_tm}.

\lstinputlisting[style=customc]{patterns/15_structs/3_tm_linux/as_array/GCC_tm2.c}

\myindex{\CStandardLibrary!localtime\_r()}
N.B. В \TT{localtime\_r} передается указатель именно на \TT{tm\_sec}, 
т.е. на первый элемент \q{структуры}.

В итоге, и этот компилятор поворчит:

\begin{lstlisting}[caption=GCC 4.7.3]
GCC_tm2.c: In function 'main':
GCC_tm2.c:11:5: warning: passing argument 2 of 'localtime_r' from incompatible pointer type [enabled by default]
In file included from GCC_tm2.c:2:0:
/usr/include/time.h:59:12: note: expected 'struct tm *' but argument is of type 'int *'
\end{lstlisting}

Тем не менее, сгенерирует такое:

\lstinputlisting[caption=GCC 4.7.3,style=customasmx86]{patterns/15_structs/3_tm_linux/as_array/GCC_tm2.asm}

Этот код почти идентичен уже рассмотренному, и нельзя сказать, была ли структура
в оригинальном исходном коде либо набор переменных.

И это работает. 
Однако, в реальности так лучше не делать. 
Обычно, неоптимизирующий компилятор располагает переменные в локальном
стеке в том же порядке, в котором они объявляются в функции.

Тем не менее, никакой гарантии нет.

Кстати, какой-нибудь другой компилятор может предупредить, что переменные \TT{tm\_year}, \TT{tm\_mon}, \TT{tm\_mday},
\TT{tm\_hour}, \TT{tm\_min}, но не \TT{tm\_sec}, используются без инициализации.
Действительно, ведь компилятор не знает что они будут заполнены при вызове функции
\TT{localtime\_r()}.

Мы выбрали именно этот пример для иллюстрации, потому что все члены структуры имеют тип \Tint.
Это не сработает, если поля структуры будут иметь размер 16 бит (\TT{WORD}), как в случае
со структурой \TT{SYSTEMTIME} --- \TT{GetSystemTime()} 
заполнит их неверно 
(потому что локальные переменные выровнены по 32-битной границе).
Читайте об этом в следующей секции: 
\q{\StructurePackingSectionName} (\myref{structure_packing}).

Так что, структура --- это просто набор переменных лежащих в одном месте, рядом.

Можно было бы сказать, что структура --- это инструкция компилятору, заставляющая его удерживать переменные в одном месте.

Кстати, когда-то, в очень ранних версиях Си (перед 1972) структур не было вовсе \RitchieDevC.

Здесь нет примера с отладчиком: потому что он будет полностью идентичным тому, что вы уже видели.

\subsubsection{Структура как массив 32-битных слов}

\lstinputlisting[style=customc]{patterns/15_structs/3_tm_linux/as_array/GCC_tm3.c}

Мы просто приводим (\IT{cast}) указатель на структуру к массиву \Tint{}-ов.
И это работает!
Запускаем пример 23:51:45 26-July-2014.

\begin{lstlisting}[label=GCC_tm3_output]
0x0000002D (45)
0x00000033 (51)
0x00000017 (23)
0x0000001A (26)
0x00000006 (6)
0x00000072 (114)
0x00000006 (6)
0x000000CE (206)
0x00000001 (1)
\end{lstlisting}

Переменные здесь в том же порядке, в котором они перечислены в определении структуры: \myref{struct_tm}.

Вот как это компилируется:

\lstinputlisting[caption=\Optimizing GCC 4.8.1,style=customasmx86]{patterns/15_structs/3_tm_linux/as_array/GCC_tm3_RU.lst}

И действительно: место в локальном стеке в начале используется как структура, затем как массив.

Возможно даже модифицировать поля структуры через указатель.

И снова, это сомнительный хакерский способ, который не рекомендуется использовать в настоящем коде.

\mysubparagraph{\Exercise}

В качестве упражнения, попробуйте модифицировать (увеличить на 1) 
текущий номер месяца обращаясь со структурой как с массивом.

\subsubsection{Структура как массив байт}

Можно пойти еще дальше. Можно привести (\IT{cast}) указатель к массиву байт и вывести его:%

\lstinputlisting[style=customc]{patterns/15_structs/3_tm_linux/as_array/GCC_tm4.c}

\begin{lstlisting}
0x2D 0x00 0x00 0x00 
0x33 0x00 0x00 0x00 
0x17 0x00 0x00 0x00 
0x1A 0x00 0x00 0x00 
0x06 0x00 0x00 0x00 
0x72 0x00 0x00 0x00 
0x06 0x00 0x00 0x00 
0xCE 0x00 0x00 0x00 
0x01 0x00 0x00 0x00 
\end{lstlisting}

Мы также запускаем этот пример в 23:51:45 26-July-2014
\footnote{Время и дата такая же в целях демонстрации. Значения байт были подправлены.}.
Переменные точно такие же, как и в предыдущем выводе 
(\myref{GCC_tm3_output}), и конечно, младший байт идет в самом начале, потому что это архитектура 
little-endian (\myref{sec:endianness}).

\lstinputlisting[caption=\Optimizing GCC 4.8.1,style=customasmx86]{patterns/15_structs/3_tm_linux/as_array/GCC_tm4_RU.lst}
